/*-*-C-*-
 * General dialogue box processing for Menu CSE
 */

#include "resed.h"
#include "main.h"

#include "wimp.h"
#include "resformat.h"
#include "newmsgs.h"
#include "dbox.h"

#include "format.h"
#include "gui.h"



/*
 * Checks to see whether a length field is exactly the right size for its
 *  corresponding string field.
 *
 * This is called when loading an object, and sets the length field to -1 if
 *  an exact* match is found; this value is then displayed as "*" in the
 *  properties dbox.
 *
 *    [* or if the length field is found to be too small - eg after import]
 */

void gui_load_len_field (char *val, int *len)
{
    if (val == NULL && *len == 0 || *len <= strlen(val) + 1)
        *len = -1;

    return;
}


/*
 * Replaces any "-1" length value by one plus the length of the associated
 *  string (or by 0 if the string is NULL).
 *
 * This is called when saving an object.
 */

void gui_save_len_field (char *val, int *len)
{
    if (*len == -1)
        *len = (val == NULL) ? 0 : strlen(val) + 1;

    return;
}


/*
 * Fill in the option, text and length fields in a dialogue box for a string
 * value which may be NULL.
 *
 * If the value is NULL, the option icon is deselected and the writable icon
 *  for the value is faded.
 */

error * gui_put_len_opt_str (
    WindowPtr dbox,       /* the dialogue box */
    int opticon,          /* the option icon */
    int valicon,          /* the writable icon to contain the text value */
    int lenicon,          /* the writable icon to contain the length value */
    char *val,            /* the text value - might be NULL */
    int len               /* the length value */
)
{
    Bool isnull = (val == NULL);

    dbox_setbutton (dbox, opticon, !isnull);
    dbox_shade (dbox, valicon, isnull);
    dbox_setstring (dbox, valicon, isnull ? "" : val);
    if (len == -1)
        dbox_setstring(dbox, lenicon, "*");
    else
        dbox_setint (dbox, lenicon, len);

    return NULL;
}


/*
 * Retrieve a string value and its length from option, text and length fields
 *  in a dialogue box.
 *
 * If the option icon is deselected, a NULL value is retrieved.
 *
 * If the option icon is selected, the length retrieved will be the greater
 *  of the value in the length field, or one more than the length of the
 *  string in the value field.
 *
 * Space for any new string value is malloc'd - and space occupied by any
 *  previous value is free'd.
 */

error * gui_get_len_opt_str (
    WindowPtr dbox,       /* the dialogue box */
    int opticon,          /* the option icon */
    int valicon,          /* the writable icon containing the text value */
    int lenicon,          /* the writable icon containing the length value */
    char **val,           /* to hold the retrieved text value - maybe NULL */
    int *len              /* to hold the retrieved length value */
)
{
    Bool isnull = !dbox_getbutton (dbox, opticon);
    char *ls = dbox_getstring(dbox, lenicon);
    int max = (*ls == '*') ? -1 : dbox_getint (dbox, lenicon);

    free (*val);

    if (isnull)
        *val = NULL;
    else
    {
        char *s = dbox_getstring (dbox, valicon);
        int n = strlen (s) + 1;

        if (max >= 0 && max < n)
            max = n;

        *val = malloc (n);
        if (*val == NULL)
            return error_lookup ("NoMem");
        strcpy (*val, s);
    }
    *len = max;

    return NULL;
}


/*
 * Fill in the option and text fields in a dialogue box for a string value
 *  which may be NULL, but which has no explicit length.
 *
 * If the value is NULL, the option icon is deselected and the writable icon
 *  for the value is faded.
 */

error * gui_put_opt_str (
    WindowPtr dbox,       /* the dialogue box */
    int opticon,          /* the option icon */
    int valicon,          /* the writable icon to contain the text value */
    char *val             /* the text value - might be NULL */
)
{
    Bool isnull = (val == NULL);

    dbox_setbutton (dbox, opticon, !isnull);
    dbox_shade (dbox, valicon, isnull);
    dbox_setstring (dbox, valicon, isnull ? "" : val);

    return NULL;
}


/*
 * Retrieve a string value from option and text fields in a dialogue box.
 *
 * If the option icon is deselected, a NULL value is retrieved.
 *
 * Space for any new string value is malloc'd - and space occupied by any
 *  previous value is free'd.
 */

error * gui_get_opt_str (
    WindowPtr dbox,       /* the dialogue box */
    int opticon,          /* the option icon */
    int valicon,          /* the writable icon containing the text value */
    char **val            /* to hold the retrieved text value - maybe NULL */
)
{
    Bool isnull = !dbox_getbutton (dbox, opticon);

    free (*val);

    if (isnull)
        *val = NULL;
    else
    {
        char *s = dbox_getstring (dbox, valicon);
        int n = strlen (s) + 1;

        *val = malloc (n);
        if (*val == NULL)
            return error_lookup ("NoMem");
        strcpy (*val, s);
    }

    return NULL;
}


/*
 * Fill in the text and length fields in a dialogue box for a mandatory
 *  string.
 *
 * A NULL value is interpreted as the empty string.
 */

error * gui_put_len_str (
    WindowPtr dbox,       /* the dialogue box */
    int valicon,          /* the writable icon to contain the text value */
    int lenicon,          /* the writable icon to contain the length value */
    char *val,            /* the text value - might be NULL */
    int len               /* the length value */
)
{
    dbox_setstring (dbox, valicon, (val == NULL) ? "" : val);

    if (len == -1)
        dbox_setstring(dbox, lenicon, "*");
    else
        dbox_setint (dbox, lenicon, len);

    return NULL;
}


/*
 * Retrieve a mandatory string value and its length from text and length
 *  fields in a dialogue box.
 *
 * If the value field contains the empty string, then a NULL value is
 *  retrieved.
 *
 * The length retrieved will be the greater of the value in the length field,
 *  or one more than the length of the string in the value field.
 *
 * Space for any new string value is malloc'd - and space occupied by any
 *  previous value is free'd.
 */

error * gui_get_len_str (
    WindowPtr dbox,       /* the dialogue box */
    int valicon,          /* the writable icon containing the text value */
    int lenicon,          /* the writable icon containing the length value */
    char **val,           /* to hold the retrieved text value - maybe NULL */
    int *len              /* to hold the retrieved length value */
)
{
    char *s = dbox_getstring (dbox, valicon);
    int n = strlen (s) + 1;
    char *ls = dbox_getstring(dbox, lenicon);
    int max = (*ls == '*') ? -1 : dbox_getint (dbox, lenicon);

    if (max >= 0 && max < n)
        max = n;

    free (*val);

    if (n == 1)       /* string is empty */
        *val = NULL;
    else
    {

        *val = malloc (n);
        if (*val == NULL)
            return error_lookup ("NoMem");
        strcpy (*val, s);
    }

    *len = max;

    return NULL;
}


/*
 * Updates the value of the length field in a dialogue box, subject to it
 *  remaining greater than or equal to zero.
 *
 * Note that if 'valicon' is set to -1, then the possibility that the length
 *  may have been given as "*" need not be considered.
 */

error * gui_adjust_len (
    WindowPtr dbox,         /* the dialogue box */
    int lenicon,            /* the writable icon containing the length */
    int valicon,            /* ... and the corresponding string */
    int delta,              /* change required (usually +/-1) */
    unsigned int modifiers  /* if SHIFT bit set, multiply by 10 */
)
{
    char *s = (valicon < 0) ? "" : dbox_getstring (dbox, lenicon);
    int len = (*s == '*') ? strlen (dbox_getstring (dbox, valicon)) + 1 :
                            dbox_getint (dbox, lenicon);

    /* SHIFT-click => adjust by tens */
    if (modifiers & MODIFIER_SHIFT)
        delta *= 10;

    len += delta;
    if (len < 0)
        len = 0;

    return dbox_setint (dbox, lenicon, len);
}


/*
 * Initialise the radio buttons and writable field for an optional event.
 *
 */

error * gui_put_opt_event (
    WindowPtr dbox,         /* the dialogue box */
    int dflticon,           /* the "raise default event" radio button */
    int othericon,          /* the "raise user-defined event" radio button */
    int noneicon,           /* the "do not raise any event" radio button */
    int valicon,            /* the writable icon containing the event */
    int val,                /* the event: 0 => default */
    Bool none               /* TRUE iff no event is to be raised */
)
{
    if (none)
    {
        dbox_setbutton (dbox, dflticon, FALSE);
        dbox_setbutton (dbox, noneicon, TRUE);
        dbox_setbutton (dbox, othericon, FALSE);
        dbox_shade (dbox, valicon, TRUE);
        dbox_setstring (dbox, valicon, "");
    }
    else
    {
        dbox_setbutton (dbox, dflticon, val == 0);
        dbox_setbutton (dbox, noneicon, FALSE);
        dbox_setbutton (dbox, othericon, val != 0);
        dbox_shade (dbox, valicon, val == 0);
        if (val == 0)
            dbox_setstring (dbox, valicon, "");
        else
            dbox_sethex (dbox, valicon, val);
    }

    return NULL;
}


/*
 * Retrieve details of an optional event from a dialogue box.
 */

error * gui_get_opt_event (
    WindowPtr dbox,
    int dflticon,
    int noneicon,
    int valicon,
    int *val,               /* event value stored here: 0 => default */
    unsigned *flags,        /* flags word to be updated */
    unsigned mask           /* identifies "no event" bit in flags */
)
{
    if (dbox_getbutton (dbox, noneicon))
        *flags &= ~mask;
    else
    {
        *flags |= mask;
        *val = dbox_getbutton (dbox, dflticon) ? 0 : 
                                 dbox_getint (dbox, valicon);
    }

    return NULL;
}


/*
 * Initialise the radio buttons and writable field for a mandatory event.
 */

error * gui_put_mand_event (
    WindowPtr dbox,         /* the dialogue box */
    int dflticon,           /* the "raise default event" radio button */
    int othericon,          /* the "raise user-defined event" radio button */
    int valicon,            /* the writable icon containing the event */
    int val                 /* the event: 0 => default */
)
{
    dbox_setbutton (dbox, dflticon, val == 0);
    dbox_setbutton (dbox, othericon, val != 0);
    dbox_shade (dbox, valicon, val == 0);
    if (val == 0)
        dbox_setstring (dbox, valicon, "");
    else
        dbox_sethex (dbox, valicon, val);

    return NULL;
}


/*
 * Retrieve details of a mandatory event from a dialogue box.
 */

error * gui_get_mand_event (
    WindowPtr dbox,
    int dflticon,
    int valicon,
    int *val
)
{
    if (dbox_getbutton (dbox, dflticon))
        *val = 0;
    else
        *val = dbox_getint (dbox, valicon);

    return NULL;
}
